/*
 * File:   ChessBoard.cpp
 * Author: Michael Ziminsky
 *
 * Created on February 28, 2011, 7:53 PM
 */

#include "ChessBoard.h"
#include "BoardEvent.h"

namespace model
{
	ChessBoard::ChessBoard() : lightTurn(true)
	{
		for (int r = 1; r <= ChessBoard::SIZE; r++)
			for (int c = 0; c < ChessBoard::SIZE; c++)
			{
				std::pair<const Location, myTypes::cPiece> p(Location(c + 'a', r), myTypes::cPiece());
				grid.insert(p);
			}
	}

	ChessBoard::ChessBoard(const ChessBoard& orig)
	{
		copy(orig);
	}

	ChessBoard& ChessBoard::operator =(const ChessBoard& orig)
	{
		copy(orig);
		return *this;
	}

	void ChessBoard::copy(const ChessBoard& orig)
	{
		lightTurn = orig.lightTurn;
		grid.insert(orig.grid.begin(), orig.grid.end());
	}

	void ChessBoard::reset()
	{
		lightTurn = true;
		for (boardMap::iterator i = grid.begin(); i != grid.end(); i++)
			removePieceAt(i->first);
	}

	void ChessBoard::addBoardListener(const IBoardListener& listener)
	{
		listeners.insert(&listener);
	}

	void ChessBoard::removeBoardListener(const IBoardListener& listener)
	{
		listeners.erase(&listener);
	}

	void ChessBoard::fireBoardChangeEvent(const Location& loc, const myTypes::cPiece& value)
	{
		BoardEvent event(this, loc, value);
		for (listenerSet::iterator i = listeners.begin(); i != listeners.end(); i++)
			if (*i) (*i)->BoardChanged(event);
			else listeners.erase(i);
	}

	/*
	 * Sets the piece at the given location to the given piece
	 * if that location is valid and does not already have a piece.
	 *
	 * @return false if there is already a piece at that location or invalid location, true otherwise.
	 */
	bool ChessBoard::setPiece(const Location& loc, const myTypes::cPiece& piece)
	{
		const Location* const l = &grid.find(loc)->first;
		myTypes::cPiece& p = grid.at(*l);
		bool empty = l && !p;
		if (empty)
		{
			if (piece) piece->setLocation(l);
			p = piece;
			fireBoardChangeEvent(loc, p);
		}
		return empty;
	}

	myTypes::cPiece ChessBoard::removePieceAt(const Location& loc)
	{
		myTypes::cPiece old = grid.at(loc);
		grid.at(loc).reset();
		if (old) old->setLocation(NULL);
		fireBoardChangeEvent(loc, grid.at(loc));
		return old;
	}

	bool ChessBoard::hasLocation(const Location& l) const
	{
		return (grid.find(l) != grid.end());
	}

	const myTypes::cPiece& ChessBoard::getPieceAt(const Location& l) const
	{
		return grid.at(l);
	}

	void ChessBoard::switchTurn()
	{
		lightTurn = !lightTurn;
	}

	bool ChessBoard::isLightTurn() const
	{
		return lightTurn;
	}

} // namespace model